package com.mall.b2c.service.impl;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;
import javax.persistence.LockModeType;

import com.mall.b2c.dao.ShopCartItemDao;
import com.mall.b2c.domain.intergral.ShopCartItemDomain;
import com.mall.b2c.domain.intergral.ShopProductDomain;
import com.mall.b2c.domain.store.StoreDomain;
import com.mall.b2c.service.*;
import net.sf.json.JSONObject;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.mall.b2c.dao.CartDao;
import com.mall.b2c.dao.CartItemDao;
import com.mall.b2c.dao.MemberDao;
import com.mall.b2c.domain.goods.GoodsDomain;
import com.mall.b2c.domain.member.MemberDomain;
import com.mall.b2c.domain.order.CartDomain;
import com.mall.b2c.domain.order.CartItemDomain;
import com.mall.common.exception.NoticeException;
import com.mall.common.hibernate.Finder;
import com.mall.common.service.impl.BaseServiceImpl;
import com.mall.common.util.SerialNumberUtil;

@Service("b2cCartService")
@Transactional(readOnly=true)
public class CartServiceImpl extends BaseServiceImpl<CartDomain, Long> implements CartService {
	@Resource private CartItemDao cartItemDao;
	@Resource private ShopCartItemDao shopCartItemDao;
	@Resource private MemberDao memberDao;
	@Resource private ReceiverService receiverService;
	@Resource private DeliveryMethodService deliveryMethodService;
	@Resource private GoodsService goodsService;
	@Resource private StoreService storeService;
	@Resource private IntergralShopProductService productService;
	
	@Resource
	public void setBaseDao(CartDao cartDao) { 
		super.setBaseDao(cartDao); 
	}
	
	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public CartDomain getCurrent(Long memberId, String key) {
		CartDomain cart = null;
		if(memberId != null){
			MemberDomain member = memberDao.find(memberId);
			if(member == null){
				throw new NoticeException("会员不存在");
			}
			memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
			cart = member.getCart();
			if(cart == null){
				cart = new CartDomain();
				cart.setMember(member);
				this.persist(cart);
			}
		}else{
			cart = get("cartKey", key);
			if(cart == null){
				cart = new CartDomain();
				cart.setCartKey(SerialNumberUtil.buildTokenSn());
				this.persist(cart);
			}
		}
		return cart;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public JSONObject addCart(Long memberId, String key, Long goodsId, Integer num) {
		if(goodsId == null){
			throw new NoticeException("商品不存在");
		}
		if(num == null || num <= 0){
			throw new NoticeException("购买数量不正确");
		}

		CartDomain cart = getCurrent(memberId, key);
		Set<CartItemDomain> itemSet = cart.getCartItemSet();
		if(itemSet == null){
			itemSet = new HashSet<CartItemDomain>();
		}
		JSONObject jObj = new JSONObject();
		for(CartItemDomain item : itemSet){
			cartItemDao.lock(item, LockModeType.PESSIMISTIC_WRITE);
			GoodsDomain goods = item.getGoods();
			if(goods.getId().equals(goodsId)){
				Integer quantity = item.getNum();
				quantity += num;
				if(goods.getIsMarketable() == null
						|| !goods.getIsMarketable()){
					throw new NoticeException("购买商品已下架");
				}
				if(goods.getStock() == null
						|| goods.getStock() < quantity){
					throw new NoticeException("商品库存不足");
				}
				item.setNum(item.getNum() + num);
				cartItemDao.merge(item);
				jObj.put("cartKey", cart.getCartKey());
				jObj.put("itemNum", itemSet.size());
				return jObj;
			}
		}
		GoodsDomain goods = goodsService.find(goodsId);
		if(goods == null){
			throw new NoticeException("商品不存在");
		}
		if(goods.getIsMarketable() == null
				|| !goods.getIsMarketable()){
			throw new NoticeException("购买商品已下架");
		}
		if(goods.getStock() == null
				|| goods.getStock() < num){
			throw new NoticeException("商品库存不足");
		}
		CartItemDomain item = new CartItemDomain();
		item.setGoods(goods);
		item.setNum(num);
		item.setCart(cart);
		cartItemDao.persist(item);

		jObj.put("cartKey", cart.getCartKey());
		jObj.put("itemNum", itemSet.size() + 1);
		return jObj;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public JSONObject addCart2(Long memberId, String key, Long id, Integer num) {
		if(id == null){
			throw new NoticeException("商品不存在");
		}
		if(num == null || num <= 0){
			throw new NoticeException("购买数量不正确");
		}

		CartDomain cart = getCurrent(memberId, key);
		Set<ShopCartItemDomain> itemSet = cart.getShopCartItems();
		if(itemSet == null){
			itemSet = new HashSet<ShopCartItemDomain>();
		}
		JSONObject jObj = new JSONObject();
		for(ShopCartItemDomain item : itemSet){
			shopCartItemDao.lock(item, LockModeType.PESSIMISTIC_WRITE);
			ShopProductDomain goods = item.getProduct();
			if(goods.getId().equals(id)){
				Integer quantity = item.getNum();
				quantity += num;
				if(goods.getNum() <= 0){
					throw new NoticeException("该积分商品库存不足");
				}
				item.setNum(quantity);
				shopCartItemDao.merge(item);
				jObj.put("cartKey", cart.getCartKey());
				jObj.put("itemNum", itemSet.size());
				return jObj;
			}
		}
		ShopProductDomain goods = productService.find(id);
		if(goods == null){
			throw new NoticeException("该积分商品不存在");
		}

		if(goods.getNum() < num){
			throw new NoticeException("该积分商品库存不足");
		}
		ShopCartItemDomain item = new ShopCartItemDomain();
		item.setProduct(goods);
		item.setNum(num);
		item.setCart(cart);
		shopCartItemDao.persist(item);

		jObj.put("cartKey", cart.getCartKey());
		jObj.put("itemNum", itemSet.size() + 1);
		return jObj;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void modifyCartItem(Long memberId, Long itemId, Integer num) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(itemId == null){
			throw new NoticeException("购买商品不存在");
		}
		if(num == null || num <= 0){
			throw new NoticeException("购买数量不正确");
		}
		Finder finder = Finder.create("from CartItemDomain bean where bean.cart.member.id = :memberId and bean.id = :itemId");
		finder.setParam("memberId", memberId);
		finder.setParam("itemId", itemId);
		Object obj = finder.findUniqueByHQL();
		if(obj == null){
			throw new NoticeException("购买商品不存在");
		}
		CartItemDomain item = (CartItemDomain) obj;
		cartItemDao.lock(item, LockModeType.PESSIMISTIC_WRITE);
		GoodsDomain goods = item.getGoods();
		if(goods.getIsMarketable() == null
				|| !goods.getIsMarketable()){
			throw new NoticeException("购买商品已下架");
		}
		if(goods.getStock() == null
				|| goods.getStock() < num){
			throw new NoticeException("商品库存不足");
		}
		item.setNum(num);
		cartItemDao.merge(item);
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void modifyCartItem2(Long memberId, Long itemId, Integer num) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(itemId == null){
			throw new NoticeException("购买积分商品不存在");
		}
		if(num == null || num <= 0){
			throw new NoticeException("购买数量不正确");
		}
		Finder finder = Finder.create("from ShopCartItemDomain bean where bean.cart.member.id = :memberId and bean.id = :itemId");
		finder.setParam("memberId", memberId);
		finder.setParam("itemId", itemId);
		Object obj = finder.findUniqueByHQL();
		if(obj == null){
			throw new NoticeException("购买积分商品不存在");
		}
		ShopCartItemDomain item = (ShopCartItemDomain) obj;
		shopCartItemDao.lock(item, LockModeType.PESSIMISTIC_WRITE);
		ShopProductDomain goods = item.getProduct();

		if(goods.getNum() < num){
			throw new NoticeException("该积分商品库存不足");
		}
		item.setNum(num);
		shopCartItemDao.merge(item);
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public JSONObject deletecartItem(Long memberId, Long[] itemIds) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(itemIds == null){
			throw new NoticeException("购买商品不存在");
		}
		Finder finder = Finder.create("from CartItemDomain bean where bean.cart.member.id = :memberId and bean.id in (:itemIds)");
		finder.setParam("memberId", memberId);
		finder.setParamList("itemIds", itemIds);
		List<CartItemDomain> list = finder.findHQLList();
		if(list.size() < itemIds.length){
			throw new NoticeException("购买商品有部分不在购物车中");
		}
		CartDomain cart = getCurrent(memberId, null);
		int count = cart.getCartItemSet().size();
		for(CartItemDomain item : list){
			cartItemDao.remove(item);
			count--;
		}
		JSONObject jObj = new JSONObject();
		jObj.put("itemNum", count);
		return jObj;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public JSONObject deletecartItem2(Long memberId, Long[] itemIds) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(itemIds == null){
			throw new NoticeException("购买商品不存在");
		}
		Finder finder = Finder.create("from ShopCartItemDomain bean where bean.cart.member.id = :memberId and bean.id in (:itemIds)");
		finder.setParam("memberId", memberId);
		finder.setParamList("itemIds", itemIds);
		List<ShopCartItemDomain> list = finder.findHQLList();
		if(list.size() < itemIds.length){
			throw new NoticeException("购买积分商品有部分不在购物车中");
		}
		CartDomain cart = getCurrent(memberId, null);
		int count = cart.getShopCartItems().size();
		for(ShopCartItemDomain item : list){
			shopCartItemDao.remove(item);
			count--;
		}
		JSONObject jObj = new JSONObject();
		jObj.put("itemNum", count);
		return jObj;
	}

	@Override
	public JSONObject checkItems(Long memberId, Long[] itemIds) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(itemIds == null){
			throw new NoticeException("购买商品不存在");
		}
		Finder finder = Finder.create("from CartItemDomain bean where bean.cart.member.id = :memberId and bean.id in (:itemIds)");
		finder.setParam("memberId", memberId);
		finder.setParamList("itemIds", itemIds);
		List<CartItemDomain> list = finder.findHQLList();
		if(list.size() < itemIds.length){
			throw new NoticeException("购买商品有部分不在购物车中");
		}
		BigDecimal weight = BigDecimal.ZERO;
		for(CartItemDomain item : list){
			GoodsDomain goods = item.getGoods();
			if(goods.getIsMarketable() == null
					|| !goods.getIsMarketable()){
				throw new NoticeException("购买商品已下架");
			}
			if(goods.getStock() == null
					|| goods.getStock() < item.getNum()){
				throw new NoticeException("商品库存不足");
			}
			if(goods.getWeight() != null){
				weight = weight.add(goods.getWeight().multiply(new BigDecimal(item.getNum())));
			}
		}
		JSONObject jObj = new JSONObject();
		jObj.put("receivers", receiverService.getRecerverList(memberId));
		jObj.put("weight", weight);
		return jObj;
	}

	@Override
	public JSONObject checkItems2(Long memberId, Long[] itemIds) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(itemIds == null){
			throw new NoticeException("购买积分商品不存在");
		}
		Finder finder = Finder.create("from ShopCartItemDomain bean where bean.cart.member.id = :memberId and bean.id in (:itemIds)");
		finder.setParam("memberId", memberId);
		finder.setParamList("itemIds", itemIds);
		List<ShopCartItemDomain> list = finder.findHQLList();
		if(list.size() < itemIds.length){
			throw new NoticeException("购买商品有部分不在购物车中");
		}
		BigDecimal weight = BigDecimal.ZERO;
		for(ShopCartItemDomain item : list){
			ShopProductDomain goods = item.getProduct();

			if(goods.getNum() < item.getNum()){
				throw new NoticeException("商品库存不足");
			}
			/*if(goods.getWeight() != null){
				weight = weight.add(goods.getWeight().multiply(new BigDecimal(item.getNum())));
			}*/
		}
		JSONObject jObj = new JSONObject();
//		jObj.put("receivers", receiverService.getRecerverList(memberId));
//		jObj.put("weight", weight);
		return jObj;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public JSONObject batchAddCartItem(Long memberId, Long[] goodsIds) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}

		CartDomain cart = getCurrent(memberId, null);
		Set<CartItemDomain> itemSet = cart.getCartItemSet();
		if(itemSet == null){
			itemSet = new HashSet<CartItemDomain>();
		}
		JSONObject jObj = new JSONObject();
		List<GoodsDomain> goodsList = goodsService.get(goodsIds);
		if(goodsList.size() != goodsIds.length){
			throw new NoticeException("部分商品不存在");
		}
		for(GoodsDomain goods : goodsList){
			CartItemDomain item = new CartItemDomain();
			item.setGoods(goods);
			item.setNum(1);
			item.setCart(cart);
			if(!itemSet.contains(item)){
				cartItemDao.persist(item);
				itemSet.add(item);
			}
		}
		jObj.put("itemNum", itemSet.size());
		return jObj;
	}
	
}
